Lektion 8



Einfache Transparenz

Die meisten Spezialeffekte in OpenGL basieren auf einer Art Blending. Blending wird benutzt, um die Farbe eines bestimmten Pixels, der gezeichnet werden soll, mit einem Pixel, der bereits auf dem Bildschirm ist, zu kombinieren. Wie die Farben kombiniert werden basiert auf dem Alpha Wert der Farben und/oder die Blending Funktion, die benutzt wird. Alpha ist die 4te Farbkomponente, die normalerweise an letzter Stelle spezifiziert wird. In der Vergangenheit haben Sie GL_RGB benutzt, um Farben mit 3 Komponenten zu spezifizieren. GL_RGBA kann benutzt werden, um auch Alpha zu spezifizieren. Zusätzlich können wir glColor4f() statt glColor3f() benutzen.

Die meisten Leute stellen sich Alpha als einen Wert vor, der angibt, wie durchsichtig das Material ist. Ein Alpha-Wert von 0.0 bedeutet, dass das Material komplett transparent ist. Ein Wert von 1.0 würde totale Undurchsichtigkeit bedeuten.

Die Blending Gleichung

Wenn Sie Mathe nicht mögen und Sie nur wissen wollen, wie das mit der Transparenz funktioniert, können Sie diesen Teil überspringen. Wenn Sie wissen wollen, wie Blending funktioniert, dann ist dieser Abschnitt genau das richtige für Sie.

(Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da)

OpenGL berechnet das Ergebnis des Blendings der zwei Pixel basierend auf dieser Gleichung durchführen. Das s und d beschreiben den Quell- und den Ziel-Pixel. Die S und D Komponenten sind die Blend-Faktoren. Diese Werte indizieren, wie Sie die Pixel blenden wollen. Die häufigsten Werte für S und D sind (As, As, As, As) (auch bekannt als Quell Alpha) für S und (1, 1, 1, 1) - (As, As, As, As) (auch bekannt als 1 minus Quell-Alpha) für D. Daraus resultiert eine Blending-Gleichung, die wie folgt aussieht:

(Rs As + Rd (1 - As), Gs As + Gd (1 - As), Bs As + Bd (1 - As), As As + Ad (1 - As))

Diese Gleichung hat als Ergebnis Transparente/Lichtdurchlässige Effekte.

Blending in OpenGL

Wir aktivieren Blending wie alles anderes auch. Dann setzen wir die Gleichung und deaktivieren das Schreiben in den Depth Buffer solange wir transparente Objekte zeichnen, da wir die Objekte, die hinter der durchsichtigen Fläche sind, auch noch zeichnen wollen. Das ist nicht der korrekte Weg für Blending, aber bei den meisten einfachen Objekten funktioniert das wunderbar. Rui Martins fügt hinzu: Der korrekte Weg ist, alle transparenten Polygone (mit Alpha < 1.0) zu zeichnen, nachdem Sie die komplette Szene gezeichnet haben und diese in umgekehrter Tiefen-Ordnung (das entfernteste als erstes) zu zeichen. Das liegt daran, dass beim blenden zweier Polygone (1 und 2) in verschiedener Reihenfolge, es verschiedene Ergebnisse gibt, z.B. angenommen Polygon 1 ist am nähsten zum Betrachter, der korrekte Weg wäre, Polygon 2 als erstes zu zeichnen und dann Polygon 1. Wenn sie drauf schauen, kommt das Licht, wie in der Realität von hinten (hinter der 2 Polygonen, die transparent sind) und muss Polygon 2 als erstes und dann Polygon 1 passieren, bevor es das Auge des Betrachters erreicht. Sie sollten DIE TRANSPARENTEN POLYGONE DER TIEFE NACH SORTIEREN und sie NACHDEM DIE GESAMTE SZENE GEZEICHNET WURDE zeichnen, mit AKTIVIERTEN DEPTH BUFFER oder Sie erhalten unkorrekte Ergebnisse. Ich weiß, dass das manchmal nervig ist, aber das ist der korrekte Weg.

Wir werden den Code aus dem letzten Tutorial benutzen. Wir starten mit dem Hinzufügen zweier neuer Variablen am Anfang des Codes. Ich werde den kompletten Code-Ausschnitt der Klarheit halber hier nochmal komplett neu schreiben.

#include < windows.h>					// Header Datei für Windows

#include < stdio.h>					// Header Datei für die Standard Ein-/Ausgabe
#include < gl\gl.h>					// Header Datei für die OpenGL32 Library

#include < gl\glu.h>					// Header Datei für die GLu32 Library

#include < gl\glaux.h>					// Header Datei für die GLaux Library


HDC		hDC=NULL;				// Privater GDI Device Context
HGLRC		hRC=NULL;				// Permanenter Rendering Context
HWND		hWnd=NULL;				// Enthält unser Fenster-Handle
HINSTANCE	hInstance;				// Enthält die Instanz der Applikation

bool	keys[256];					// Array das für die Tastatur Routine verwendet wird
bool	active=TRUE;					// Fenster Aktiv Flag ist standardmäßig auf TRUE gesetzt
bool	fullscreen=TRUE;				// Fullscreen Flag ist standardmäßig gesetzt
bool	light;						// Beleuchtung AN/AUS
bool    blend;						// Blending AUS/AN? ( NEW )
bool	lp;						// L gedrückt?
bool	fp;						// F gedrückt?
bool	bp;						// B gedrückt? ( NEU )

GLfloat	xrot;						// X Rotation
GLfloat	yrot;						// Y Rotation
GLfloat xspeed;						// X Rotationsgeschwindigkeit
GLfloat yspeed;						// Y Rotationsgeschwindigkeit

GLfloat	z=-5.0f;					// Tiefe in den Bildschirm hinein

GLfloat LightAmbient[]=  { 0.5f, 0.5f, 0.5f, 1.0f };	// Ambiente Licht Werte
GLfloat LightDiffuse[]=	 { 1.0f, 1.0f, 1.0f, 1.0f };	// Diffuse Licht Werte
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };	// Licht Position

GLuint	filter;						// Welcher Filter benutzt werden soll
GLuint	texture[3];					// Speicher für 3 Texturen

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	// Deklaration für WndProc

Gehen Sie runter zu LoadGLTextures(). Finden Sie die Zeile: if (TextureImage[0]=LoadBMP("Data/Crate.bmp")). Ändern Sie sie in die folgende Zeile. Wir benutzen statt der Kisten-Textur für dieses Tutorial eine Glas-artige Textur.

	if (TextureImage[0]=LoadBMP("Data/glass.bmp"))	// Lädt das Glass Bitmap ( MODIFIZIERT )
 

Fügen Sie die folgenden zwei Zeilen irgendwo in den InitGL() Code ein. Diese Zeilen setzen die Helligkeit des zu zeichnenden Objekts auf volle Helligkeit mit 50% Alpha (Undurchsichtigkeit). Das bedeutet, wenn Blending aktiviert ist, ist das Objekt zu 50% Transparent. Die zweite Zeile setzt die Blending-Art, die wir benutzen wollen.

Rui Martins fügt hinzu: Ein Alpha Wert von 0.0 würde bedeuten, dass das Material komplett Transparent ist. Ein Wert von 1.0 würde totale Undurchsichtigkeit bedeuten.

	glColor4f(1.0f,1.0f,1.0f,0.5f);			// Volle Helligkeit, 50% Alpha ( NEU )
	glBlendFunc(GL_SRC_ALPHA,GL_ONE);		// Blending Funktion für Durchsichtigkeit basiered auf dem Quell Alpha Wert ( NEU )

Schauen Sie sich die folgende Code-Sektion an, die ganz am Ende von Lektion 7 gefunden werden kann.

	if (keys[VK_LEFT])				// Wurde die linke Pfeil-Taste gedrückt?
	{
		yspeed-=0.01f;				// Wenn ja, dekrementiere yspeed
	}

Direkt unter den obigen Code, wollen wir folgende Zeilen einfügen. Die unteren Zeilen überprüfen, ob die Taste 'B' gedrückt wurde. Wenn sie gedrückt wurde, wird überprüft, ob Blending ein- oder ausgeschaltet ist. Wenn Blending eingeschaltet ist, wird es ausgeschaltet. Ist Blending ausgeschaltet, wird es eingeschaltet.

	if (keys['B'] && !bp)				// Ist Taste B gedrückt und bp gleich FALSE?
	{
		bp=TRUE;				// Wenn ja, setze bp auf TRUE
		blend = !blend;				// Tausche den Status von blend auf TRUE / FALSE	
		if(blend)				// Ist blend gleich TRUE?
		{
			glEnable(GL_BLEND);		// Schalte Blending ein
			glDisable(GL_DEPTH_TEST);	// Schalte Depth Testing aus
		}
		else					// Ansonsten
		{
			glDisable(GL_BLEND);		// Schalte Blending aus
			glEnable(GL_DEPTH_TEST);	// Schalte Depth Testing an
		}
	}
	if (!keys['B'])					// Wurde die B Taste losgelassen?
	{
		bp=FALSE;				// Wenn ja, wird bp auf FALSE gesetzt
	}

Aber wie können wir die Farbe spezifizieren, wenn wir eine Textur-Map benutzen? Ganz einfach, im modulierten Texturmodus wird jeder Pixel der auf die Textur gemapped wird mit der aktuellen Farbe multipliziert. Wenn die zu zeichnende Farbe also (0.5, 0.6, 0.4) ist, multiplizieren wir sie mit der Anzahl der Farben und wir erhalten (0.5, 0.6, 0.4, 0.2) (es wird dabei angenommen, dass Alpha gleich 1.0 ist, wenn nichts angegeben ist).

Das war's! Blending ist eigentlich ganz einfach in OpenGL zu realisieren.

Anmerkung (11/13/99)

Ich ( NeHe ) habe den Blending Code so modifiziert, so dass das Ergebnis der Objekte eher so aussieht, wie es eigentlich soll. Verwendet man Alpha Werte für die Quelle und das Ziel, um Blending zu erzeugen, werden Artefakte erzeugt. Diese lassen die hinteren Seiten dunkler erscheinen, ebenso wie die seitlichen Seiten. Grundsätzlich würde das Objekt recht verhunzt aussehen. Die Art wie ich Blending benutze, mag nicht der Beste sein, aber es funktioniert und das Objekt erscheint so, wie es aussehen soll, wenn die Beleuchtung aktiviert ist. Danke an Tom für den ursprünglichen Code, die Art wie er Blending benutzte war der korrekte Wert, um mit Alpha-Werten zu blenden, aber es sah nicht so attratktiv aus, wie es die Leute erwartet haben ;).

Der Code wurde nochmal etwas verändert, um Adressierungsprobleme die einige Grafikkarten mit glDepthMask() hatten, zu umgehen. Es sieht so aus, dass dieser Befehl auf einigen Karten den Depth-Buffer-Test nicht korrekt aktivieren und deaktivieren, weshalb ich zurück zum guten alten glEnable und glDisable zurückgekehrt bin, um Depth zu testen.

Alpha aus Texture Maps.

Der Alphawert, der für die Transparenz genutzt wird, kann aus einer Texture Map gelesen werden, genauso wie eine Farbe. Dafür benötigen Sie einen Alphawert in Ihrem Bild, dass Sie laden wollen und benutzen dann GL_RGBA als Farbformat im Aufruf von glTe